home *** CD-ROM | disk | FTP | other *** search
- /*
- * CBLibrary - ViewsMenu
- * Copyright (C) 2003 Chris Bazley
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
- /* General code to maintain a list of views and build iconbar menu */
-
- /* ANSI library files */
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdbool.h>
- #include <ctype.h>
-
- /* RISC OS library files */
- #include "kernel.h"
- #include "wimp.h"
- #include "toolbox.h"
- #include "saveas.h"
- #include "window.h"
- #include "event.h"
- #include "wimplib.h"
- #include "menu.h"
-
- /* My library files */
- #include "err.h"
- #include "msgtrans.h"
- #include "hourglass.h"
- #include "Macros.h"
- #include "ViewsMenu.h"
-
- typedef struct _ViewInfo {
- ObjectId object;
- char name[256]; /* to show in menu */
- char *file_path; /* to avoid loading duplicate files */
- bool remove_me;
- struct _ViewInfo *next;
- } ViewInfo;
-
- static ComponentId VM_parent_entry;
- static ViewInfo *view_list;
- static ObjectId VM, VM_parent;
- static bool menu_showing = false, removals_pending = false;
- extern _kernel_oserror shared_err_block;
-
- /* ----------------------------------------------------------------------- */
- /* Function prototypes */
-
- static ToolboxEventHandler _ViewsMenu_parentopenhandler, _ViewsMenu_clickhandler, _ViewsMenu_parentclosehandler;
-
- /* ----------------------------------------------------------------------- */
- /* Public functions */
-
- _kernel_oserror *ViewsMenu_create(void)
- {
- /* Call to create views menu (before any other function!) */
-
- /* Create menu */
- THROW(toolbox_create_object(0, "ViewsMenu", &VM))
-
- /* Listen for clicks */
- return event_register_toolbox_handler(VM, Menu_Selection, _ViewsMenu_clickhandler, NULL);
- }
-
- /* ----------------------------------------------------------------------- */
-
- _kernel_oserror *ViewsMenu_parentcreated(ObjectId parent_menu, ComponentId parent_entry)
- {
- /* To be called when parent menu is created */
- VM_parent_entry = parent_entry;
- VM_parent = parent_menu;
-
- /* Register event handlers for when parent is opened and closed */
- THROW(event_register_toolbox_handler(parent_menu, Menu_AboutToBeShown, _ViewsMenu_parentopenhandler, NULL))
- return event_register_toolbox_handler(parent_menu, Menu_HasBeenHidden, _ViewsMenu_parentclosehandler, NULL);
- }
-
- /* ----------------------------------------------------------------------- */
-
- _kernel_oserror *ViewsMenu_setname(ObjectId showobject, char *view_name, char *file_path)
- {
- ViewInfo *scan_views;
- char *new_ptr;
-
- scan_views = view_list;
- while(scan_views != NULL) {
- if(scan_views->object == showobject && !scan_views->remove_me ) {
- /* Found specified menu entry */
- if(file_path != NULL) {
- /* Change filepath associated with this menu entry */
- new_ptr = malloc(strlen(file_path)+1);
- if(new_ptr == NULL) {
- WRITE_GERR(shared_err_block, "NoMem");
- return &shared_err_block;
- }
- strcpy(new_ptr, file_path);
- free(scan_views->file_path);
- scan_views->file_path = new_ptr;
- }
- if(view_name != NULL) {
- /* Change text for this menu entry */
- THROW(menu_set_entry_text(0, VM, (ComponentId)scan_views, view_name))
- }
- return NULL; /* success */
- }
- scan_views = scan_views->next;
- }
-
- strncpy(shared_err_block.errmess, "ObjectId not found (ViewsMenu_setname)", sizeof(shared_err_block.errmess)-1);
- return &shared_err_block; /* not found */
- }
-
- /* ----------------------------------------------------------------------- */
-
- ObjectId ViewMenu_getfirst(void)
- {
- ViewInfo *scan_views;
-
- scan_views = view_list;
- while(scan_views != NULL) {
- if(!scan_views->remove_me)
- return view_list->object; /* success */
- scan_views = scan_views->next;
- }
- return NULL_ObjectId; /* not found */
- }
-
- /* ----------------------------------------------------------------------- */
-
- ObjectId ViewMenu_getnext(ObjectId current)
- {
- ViewInfo *scan_views;
-
- scan_views = view_list;
- while(scan_views != NULL) {
- if(scan_views->object == current && !scan_views->remove_me
- && scan_views->next != NULL && !scan_views->next->remove_me)
- return scan_views->next->object; /* found */
-
- scan_views = scan_views->next;
- }
-
- return NULL_ObjectId; /* 'current' view not found, or end of list */
- }
-
- /* ----------------------------------------------------------------------- */
-
- _kernel_oserror *ViewsMenu_add(ObjectId showobject, char *view_name, char *file_path)
- {
- ViewInfo *new_view;
- MenuTemplateEntry Entry = {0};
- ViewInfo *scan_views;
- _kernel_oserror *errptr;
-
- /* Check not already on list */
- scan_views = view_list;
- while(scan_views != NULL) {
- if(scan_views->object == showobject && !scan_views->remove_me) {
- strncpy(shared_err_block.errmess, "Duplicate ObjectId (ViewsMenu_add)", sizeof(shared_err_block.errmess)-1);
- return &shared_err_block;
- }
- scan_views = scan_views->next;
- }
-
- /* Create new menu entry */
- new_view = malloc(sizeof(ViewInfo));
- if(new_view == NULL) {
- WRITE_GERR(shared_err_block, "NoMem");
- return &shared_err_block;
- }
-
- /* Set entry text, and associated toolbox object & filepath */
- new_view->remove_me = false;
- new_view->file_path = malloc(strlen(file_path)+1);
- if(new_view->file_path == NULL) {
- free(new_view);
- WRITE_GERR(shared_err_block, "NoMem");
- return &shared_err_block; /* failure */
- }
- strcpy(new_view->file_path, file_path);
- new_view->object = showobject;
- strncpy(new_view->name, view_name, sizeof(new_view->name)-1);
-
- /* Add entry to menu */
- Entry.text = new_view->name;
- Entry.max_text = sizeof(new_view->name);
- Entry.component_id = (ComponentId)new_view;
- errptr = menu_add_entry(0, VM, Menu_AddEntryAtEnd, (char *) &Entry, 0);
- if(errptr != NULL) {
- free(new_view->file_path);
- free(new_view);
- return errptr; /* failure */
- }
-
- /* Link new menu entry into list */
- new_view->next = view_list;
- view_list = new_view;
-
- return NULL; /* success */
- }
-
- /* ----------------------------------------------------------------------- */
-
- _kernel_oserror *ViewsMenu_showall(void)
- {
- /* Bring all open windows to the front */
- ViewInfo *scan_views;
- ObjectId parent;
- unsigned int state;
- ComponentId parent_component;
-
- scan_views = view_list;
- while(scan_views != NULL) {
- if(!scan_views->remove_me) {
- /* Show object using existing parent */
- THROW(toolbox_get_parent(0, scan_views->object, &parent, &parent_component))
- /* Trap incase parent no longer exists */
- if(toolbox_get_object_state(0, parent, &state) != NULL) {
- parent = NULL_ObjectId;
- parent_component = NULL_ComponentId;
- }
- THROW(ViewsMenu_show_object(0, scan_views->object, Toolbox_ShowObject_Default, NULL, parent, parent_component))
-
- scan_views = scan_views->next;
- }
- }
- return NULL; /* success */
- }
-
- /* ----------------------------------------------------------------------- */
-
- _kernel_oserror *ViewsMenu_remove(ObjectId showobject)
- {
- /* Remove a window from the list */
- ViewInfo *scan_views, *prev_view;
-
- scan_views = view_list;
- prev_view = NULL;
- while(scan_views != NULL) {
- if(scan_views->object == showobject
- && !scan_views->remove_me) {
- free(scan_views->file_path); /* can immediately do without wasting this memory */
- /* Is views menu showing? */
- if(menu_showing) {
- /* Removing entry seems to cause trouble if menu is open */
- scan_views->remove_me = true;
- removals_pending = true;
- /* (Removal defered until menu closes. Must keep linked list record or we will lose the ComponentId of the menu entry.) */
- }
- else {
- /* Menu is closed - safe to remove menu entry */
- THROW(menu_remove_entry(0, VM, (ComponentId)scan_views))
-
- /* Link over record */
- if(scan_views == view_list)
- view_list = scan_views->next;
- else
- prev_view->next = scan_views->next;
- free(scan_views);
- }
- return NULL; /* success */
- }
- prev_view = scan_views;
- scan_views = scan_views->next;
- }
- strncpy(shared_err_block.errmess, "ObjectId not found (ViewsMenu_remove)", sizeof(shared_err_block.errmess)-1);
- return &shared_err_block; /* not found */
- }
-
- /* ----------------------------------------------------------------------- */
-
- ObjectId ViewsMenu_findview(char *file_path_to_match)
- {
- /* Find a view matching the specified name */
- ViewInfo *scan_views;
-
- scan_views = view_list;
- while(scan_views != NULL) {
- if(ViewsMenu_strcmp_nc(scan_views->file_path, file_path_to_match)
- && !scan_views->remove_me)
- return scan_views->object; /* found matching path */
- scan_views = scan_views->next;
- }
- return NULL_ObjectId; /* not found */
- }
-
- /* ----------------------------------------------------------------------- */
-
- bool ViewsMenu_strcmp_nc(const char *string1, const char *string2)
- {
- /* Determines whether two strings are equal, case insensitive */
- int i = 0;
- while(string1[i] != 0 && string2[i] != 0
- && tolower((int)string1[i]) == tolower((int)string2[i]))
- i++;
- if(string1[i] == 0 && string2[i] == 0)
- return true; /* reached string terminators */
- return false; /* finished early due to mismatch */
- }
-
- /* ----------------------------------------------------------------------- */
-
- _kernel_oserror *ViewsMenu_show_object(unsigned int flags, ObjectId id, int show_type, void *type, ObjectId parent, ComponentId parent_component)
- {
- /* This addresses the problem of iconised windows being re-opened independently by an application, yet remaining on the pinboard */
-
- THROW(toolbox_show_object(flags, id, show_type, type, parent, parent_component))
-
- ObjectClass obj_class;
- THROW(toolbox_get_object_class(0, id, &obj_class))
- if(obj_class == SaveAs_ObjectClass)
- THROW(saveas_get_window_id(0, id, &id))
- else {
- if(obj_class != Window_ObjectClass)
- return NULL; /* don't know about other classes */
- }
-
- /* Get wimp handle of underlying window */
- WimpMessage msg_block;
- THROW(window_get_wimp_handle(0, id, &msg_block.data.words[0]))
-
- /* Broadcast message &400CB (window closed) in case it is iconised */
- msg_block.hdr.size = sizeof(msg_block.hdr) + sizeof(int);
- msg_block.hdr.your_ref = 0;
- msg_block.hdr.action_code = Wimp_MWindowClosed;
- return wimp_send_message(Wimp_EUserMessage, &msg_block, 0, 0, NULL);
- }
-
- /* ----------------------------------------------------------------------- */
- /* Private functions */
-
- static int _ViewsMenu_parentopenhandler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
- {
- /* Parent of views menu is about to open */
- NOT_USED(event_code)
- NOT_USED(event)
- NOT_USED(handle)
-
- /* If linked list is empty then grey views submenu entry */
- RE(menu_set_fade(0, id_block->self_id, VM_parent_entry, (view_list == NULL)))
-
- menu_showing = true; /* we need to defer deletions until menu closes */
-
- return 0; /* pass event on (not our menu!) */
- }
-
- /* ----------------------------------------------------------------------- */
-
- static int _ViewsMenu_parentclosehandler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
- {
- /* Parent of views menu has closed */
- ViewInfo *scan_views, *prev_view, *delscan_view;
- NOT_USED(event_code)
- NOT_USED(event)
- NOT_USED(id_block)
- NOT_USED(handle)
-
- menu_showing = false; /* we no longer need to defer deletions */
-
- if(removals_pending) {
- /* Remove any entries on views menu that have been greyed out (i.e. window closed) */
- scan_views = view_list;
- prev_view = NULL;
- while(scan_views != NULL) {
- if(scan_views->remove_me) {
- /* Remove menu entry */
- RE(menu_remove_entry(0, VM, (ComponentId)scan_views))
- delscan_view = scan_views;
- scan_views = delscan_view->next;
- /* (prev_view stays the same - record before deleted record) */
-
- /* Link over record */
- if(view_list == delscan_view)
- view_list = scan_views;
- else
- prev_view->next = scan_views;
- free(delscan_view);
- }
- else {
- /* roll onto next record in linked list */
- prev_view = scan_views;
- scan_views = scan_views->next;
- }
- }
- removals_pending = false;
- }
- return 1; /* claim event */
- }
-
- /* ----------------------------------------------------------------------- */
-
- static int _ViewsMenu_clickhandler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
- {
- ViewInfo *view_info;
- ObjectId parent;
- ComponentId parent_component;
- unsigned int state;
- NOT_USED(event_code)
- NOT_USED(event)
- NOT_USED(handle)
-
- view_info = (ViewInfo *)id_block->self_component;
- if(view_info->remove_me) {
- _kernel_oswrch(7); /* beep */
- return 1; /* object no longer exists */
- }
-
- /* Get parent of object associated with this menu entry */
- E_RETV(toolbox_get_parent(0, view_info->object, &parent, &parent_component), 1)
-
- /* Trap incase parent no longer exists */
- if(toolbox_get_object_state(0, parent, &state) != NULL) {
- parent = NULL_ObjectId;
- parent_component = NULL_ComponentId;
- }
- /* Re-open, preserving current parent */
- RE(ViewsMenu_show_object(0, view_info->object, Toolbox_ShowObject_Default, NULL, parent, parent_component))
-
- return 1; /* claim event */
- }
-